package com.weyoung.app.service.impl;


import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weyoung.app.controller.FileController;
import com.weyoung.app.dto.req.AddGraNodeDTO;
import com.weyoung.app.dto.req.GraNodeMessage;
import com.weyoung.app.service.GraveVisitingNodeService;
import com.weyoung.app.mapper.GraveVisitingNodeMapper;
import com.weyoung.app.service.UserService;
import com.weyoung.common.config.RabbitMQConfig;
import com.weyoung.common.consatant.exception.ServiceException;
import com.weyoung.common.consatant.result.Result;
import com.weyoung.common.model.entity.GraveVisitingNode;
import com.weyoung.common.model.entity.UserDO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.weyoung.common.utils.RedisConstants.*;

/**
* @author 27675
* @description 针对表【grave_visiting_node(扫墓节点表)】的数据库操作Service实现
* @createDate 2025-04-15 11:28:03
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class GraveVisitingNodeServiceImpl extends ServiceImpl<GraveVisitingNodeMapper, GraveVisitingNode>
    implements GraveVisitingNodeService{

    private final UserService userService;
    private final StringRedisTemplate stringRedisTemplate;
    private final FileController fileController;
    private final GraveVisitingNodeMapper graveVisitingNodeMapper;
    private final RabbitTemplate rabbitTemplate;

    /**
     * 添加扫墓节点
     * @param addGraNodeDTO
     * @return
     */
    @Override
    public Result addGraveNode(AddGraNodeDTO addGraNodeDTO, MultipartFile file) {
        // 参数校验 - 确保输入数据的有效性
        validateAddGraNodeDTO(addGraNodeDTO);
        // 复制输入信息
        GraveVisitingNode graveVisitingNode;
        // 获取用户信息
        Integer userId = Integer.parseInt(StpUtil.getLoginId().toString());
        UserDO userDO = userService.getById(userId);
        if (userDO == null || StrUtil.isBlank(userDO.getFamilyId())){
            log.error("添加扫墓节点失败，用户ID: {}, 请求参数: {}", userId, addGraNodeDTO);
            return Result.failure("1","用户未加入家庭");
        }
        // 插入数据
        graveVisitingNode = buildGraveVisitingNode(addGraNodeDTO, userDO);
        log.debug("用户ID：{} 开始添加扫墓节点，节点信息: {}", userId, graveVisitingNode);
        // todo 上传文件
        log.debug("用户ID：{} 开始上传扫墓节点图片，图片信息: {}", userId, file);
        if (file != null && !file.isEmpty()) {
            try {
                String fileUrl = fileController.uploadIcon(file).getData();
                log.debug("用户ID：{} 上传扫墓节点图片成功，图片路径: {}", userId, fileUrl);
                graveVisitingNode.setPhotoUrl(fileUrl); // 将URL设置到DTO
            } catch (Exception e) {
                log.error("文件上传失败: {}", e.getMessage());
                return Result.failure("2", "文件上传失败");
            }
        }
        // 成功校验
        if (!save(graveVisitingNode)){
            log.error("添加扫墓节点失败，用户ID: {}, 请求参数: {}", userId, addGraNodeDTO);
            return Result.failure("1","添加扫墓节点失败");
        }
        log.info("添加扫墓节点成功，创建用户ID: {}, 墓地信息: {}", userId, graveVisitingNode);
        // 消息队列异步删除列表缓存
        rabbitTemplate.convertAndSend(RabbitMQConfig.GRAVE_EXCHANGE_NAME,
                RabbitMQConfig.GRAVE_ROUTING_KEY,
                buildGraNodeMessage(graveVisitingNode.getNodeId(), userDO.getFamilyId()));
        return Result.success(graveVisitingNode);

    }

    /**
     * 获取扫墓节点详情
     * @param nodeId
     * @return
     */
    @Override
    public Result getGraveNode(Integer nodeId) {
        if (nodeId == null){
            return Result.failure("1","参数不能为空");
        }
        // 查询缓存
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(GRAVE_VISITING_NODE_KEY + nodeId))){
            String JsonStr = stringRedisTemplate.opsForValue().get(GRAVE_VISITING_NODE_KEY + nodeId);
            if (StrUtil.isBlank(JsonStr)){
                return Result.failure("1","未找到对应节点记录");
            }
            // 缓存命中，直接返回相关信息
            GraveVisitingNode graveVisitingNode = BeanUtil.toBean(JsonStr, GraveVisitingNode.class);
            log.info("用户ID：{} 查询到缓存信息，节点ID: {}, 节点信息: {}", StpUtil.getLoginId(),nodeId, graveVisitingNode);
            return Result.success(graveVisitingNode);
        }
        // 缓存未命中，查询数据库
        GraveVisitingNode graveVisitingNode = getById(nodeId);
        if (graveVisitingNode == null){
            // 数据库未找到
            // 存入空数据入缓存
            stringRedisTemplate.opsForValue().set(GRAVE_VISITING_NODE_KEY + nodeId, "");
            stringRedisTemplate.expire(GRAVE_VISITING_NODE_KEY + nodeId, NULL_EXPIRE_TIME, TimeUnit.SECONDS);
            // 返回错误
            log.info("用户ID：{} 尝试查询非法墓地节点ID，节点ID: {}, 节点信息: {}",
                    StpUtil.getLoginId(),nodeId, null);
            return Result.failure("1","未找到对应节点记录");
        }
        // 数据库找到
        String JsonStr = JSONUtil.toJsonStr(graveVisitingNode);
        stringRedisTemplate.opsForValue().set(GRAVE_VISITING_NODE_KEY + nodeId, JsonStr);
        stringRedisTemplate.expire(
                GRAVE_VISITING_NODE_KEY + nodeId,
                GRAVE_VISITING_NODE_EXPIRE_TIME + RandomUtil.randomLong(20),
                TimeUnit.MINUTES);
        log.info("用户ID：{} 查询到墓地数据库信息，节点ID: {}, 节点信息: {}", StpUtil.getLoginId(),nodeId, graveVisitingNode);
        return Result.success(graveVisitingNode);
    }

    /**
     * 获得扫墓节点列表
     * @return
     */
    @Override
    public Result getGraveNodeList() {
        // 获取用户信息
        int userId = Integer.parseInt(StpUtil.getLoginId().toString());
        UserDO userDO = userService.getById(userId);
        // 查看家族缓存
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(GRAVE_VISITING_NODE_LIST_KEY + userDO.getFamilyId()))){
            // 缓存存在
            String JsonStr = stringRedisTemplate.opsForValue().get(GRAVE_VISITING_NODE_LIST_KEY + userDO.getFamilyId());
            // 判断空值
            if (StrUtil.isBlank(JsonStr)){
                // 缓存为空
                return Result.failure("1","未找到对应家族墓地记录");
            }
            // 不为空，转换实体
            List<GraveVisitingNode> graveVisitingNodes = JSONUtil.toList(JsonStr, GraveVisitingNode.class);
            // 返回成功
            log.info("用户ID：{} 查询到缓存信息，家族ID: {}, 列表信息: {}", StpUtil.getLoginId(),userDO.getFamilyId(), graveVisitingNodes);
            return Result.success(graveVisitingNodes);
        }
        // 缓存不存在，查询数据库
        List<GraveVisitingNode> graveVisitingNodes = list(new QueryWrapper<GraveVisitingNode>().eq("family_id", userDO.getFamilyId()).ne("is_deleted", "1"));
        if (graveVisitingNodes == null || graveVisitingNodes.isEmpty()){
            // 数据库未找到
            // 存入空数据入缓存
            stringRedisTemplate.opsForValue().set(GRAVE_VISITING_NODE_LIST_KEY + userDO.getFamilyId(), "");
            stringRedisTemplate.expire(GRAVE_VISITING_NODE_LIST_KEY + userDO.getFamilyId(), NULL_EXPIRE_TIME, TimeUnit.SECONDS);
            // 返回错误
            log.info("用户ID：{} 尝试查询非法家族ID，家族ID: {}, 列表信息: {}", StpUtil.getLoginId(),userDO.getFamilyId(), null);
            return Result.failure("1","未找到对应家族墓地记录");
        }
        // 数据库获取成功，返回对应列表数据
        String JsonStr = JSONUtil.toJsonStr(graveVisitingNodes);
        stringRedisTemplate.opsForValue().set(GRAVE_VISITING_NODE_LIST_KEY + userDO.getFamilyId(), JsonStr);
        stringRedisTemplate.expire(GRAVE_VISITING_NODE_LIST_KEY + userDO.getFamilyId(),
                GRAVE_VISITING_NODE_LIST_EXPIRE_TIME + RandomUtil.randomLong(20),
                TimeUnit.MINUTES);
        log.info("用户ID：{} 查询到墓地数据库信息，家族ID: {}, 列表信息: {}", StpUtil.getLoginId(),userDO.getFamilyId(), graveVisitingNodes);
        return Result.success(graveVisitingNodes);
    }

    /**
     * 逻辑删除
     * @param id
     * @return
     */
    @Override
    public Result deleteGraveNode(Integer id) {

        // 先找缓存
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(GRAVE_VISITING_NODE_KEY + id))){
            String jsonStr = stringRedisTemplate.opsForValue().get(GRAVE_VISITING_NODE_KEY + id);
            if (StrUtil.isBlank(jsonStr)){
                throw new ServiceException("要删除的节点不存在");
            }
            // 缓存不为空
            GraveVisitingNode graveVisitingNode = JSONUtil.toBean(jsonStr, GraveVisitingNode.class);
            if (!graveVisitingNodeMapper.deleteByNodeId(id)){
                throw new ServiceException("删除失败");
            }
            // 构建消息
            // 删除后发送消息到消息队列处理数据一致性
            rabbitTemplate.convertAndSend(RabbitMQConfig.GRAVE_EXCHANGE_NAME,
                    RabbitMQConfig.GRAVE_ROUTING_KEY,
                    buildGraNodeMessage(id,graveVisitingNode.getFamilyId()));// 发送消息异步处理

            return Result.success("删除成功");
        }
        // 缓存不存在
        GraveVisitingNode graveVisitingNode = getById(id);
        if (id == null){
            return Result.failure("1","参数不能为空");
        }
        if (!graveVisitingNodeMapper.deleteByNodeId(id)){
                throw new ServiceException("删除失败");
        }
        // 删除后发送消息到消息队列处理数据一致性
        rabbitTemplate.convertAndSend(RabbitMQConfig.GRAVE_EXCHANGE_NAME,// 发送到交换机
                RabbitMQConfig.GRAVE_ROUTING_KEY,// 订阅路由
                buildGraNodeMessage(id,graveVisitingNode.getFamilyId()));// 发送消息
        return Result.success("删除成功");

    }

    /**
     * 消息实体构建器
     * @param nodeId
     * @param familyId
     * @return
     */
    private GraNodeMessage buildGraNodeMessage(Integer nodeId,String familyId) {
        GraNodeMessage graNodeMessage = new GraNodeMessage();
        graNodeMessage.setNodeId(nodeId);
        graNodeMessage.setFamilyId(familyId);
        return graNodeMessage;
    }
    /**
     * 验证添加扫墓节点DTO参数
     * @param dto 待验证的DTO对象
     */
    private void validateAddGraNodeDTO(AddGraNodeDTO dto) {
        // 基础非空检查
        if (dto == null) {
            Result.failure("1","参数不能为空");
        }
        // 墓主人姓名检查
        if (dto != null && (StrUtil.isBlank(dto.getDeceasedName()) || StrUtil.isBlank(dto.getDeceasedTitle()))) {
            Result.failure("1", "墓主人姓名 / 称谓不能为空");
        }
        // 墓地位置检查
        if (dto != null && StrUtil.isBlank(dto.getLocation())) {
            Result.failure("1", "墓地位置不能为空");
        }
        // 经纬度格式验证（如果有）
        if (dto != null && dto.getLongitude() != null) {
            Result.failure("1", "经度值不合法");
        }
        if (dto != null && dto.getLatitude() != null) {
            Result.failure("1", "纬度值不合法");
        }
    }

    /**
     * 构建扫墓节点实体对象
     * @param dto 数据传输对象
     * @param currentUser 当前登录用户
     * @return 构建好的扫墓节点实体
     */
    private GraveVisitingNode buildGraveVisitingNode(AddGraNodeDTO dto, UserDO currentUser) {
        GraveVisitingNode node = new GraveVisitingNode();
        // 复制简单属性
        BeanUtil.copyProperties(dto, node);

        // 设置系统属性
        LocalDateTime now = LocalDateTime.now();
        node.setCreateDate(now);
        node.setUpdateDate(now);
        node.setCreatorId(currentUser.getUserId());
        node.setFamilyId(currentUser.getFamilyId());
        node.setIsDeleted("0"); // 使用数字代替枚举，与数据库定义一致

        return node;
    }
}











